#pragma once

#include "DataBase.h"
#include <core/strings/string_aes.h>

typedef qb::base::BlockAes BlockAes;
namespace qb{
	namespace ht{
		class TableFileView{
			int			m_size;			// 视图大小，通常都是view size的倍数
			int			m_start;		// 在文件中的偏移量,是系统PAGE_SIZE的整数倍
			char*		m_view;			// 映射好的内存，后续需要解决使用试用一个内存地址去映射
			char*		m_last;			// 上一个m_view指针,用于绑定一个内存位置,反复使用
		public:
            TableFileView() :m_size(0), m_start(0), m_view(0), m_last(0){}
			~TableFileView(){}
			int GetViewSize()const{ return m_size; }
			int GetStart()const{ return m_start; }
            bool Acquire(void* mapping, int start, int size);
			void Release();
			bool Contains(int offset, int size)const{
				return offset >= m_start && offset + size <= m_start + m_size;
			}
			const char* GetView()const{ return m_view; }
			void Write(int offset,const char* record, int size);
			void Read(int offset, char* record, int size)const;
		};

		class TableFile{
			enum{
				MEGA_BYTES = 1024 * 1024,
			};
		protected://静态值不变量
			int				m_increase_size;			// 文件每次变大递增的尺寸,默认32mb
			int				m_sys_pagesize;				// 系统的页面大小,分配内存即按照此对齐
			int				m_view_size;				// 每次映射的内存尺寸,越大占用内存越多
			int				m_init_pos;					// 初始文件尺寸;
			
		protected://映射文件相关
			int				m_max_size;					// 最大文件大小
			int				m_max_viewid;				// 当前能映射的最大viewid
#ifdef WIN32
            void*			m_file;						// 文件句柄
#else
            int             m_file;						// 文件句柄
#endif
            void*			m_mapping;					// 映射文件句柄
            TableFileView	m_fview;					// 映射文件区域,随机映射区域,
			TableFileView	m_head_view;				// 头部映射区域,只管辖[0,m_head_view_size]

			bool			m_head_reset;				// m_head_view是否已经重置了
			bool			m_initialized;				// 是否已经初始化了
			
			std::string		m_fname;					// 映射文件名称，用于删除
			int				m_remap_count;				// 重新映射的次数,数值越大,说明性能不好
		protected://文件头相关
			int				m_record_count;				// 总共记录个数,也包括无效记录个数,每次写入新的记录,此个数都会增加
			int				m_head_size;				// 文件头部尺寸,有效尺寸
			int				m_head_view_size;			// 比m_head_size大,是m_sys_pagesize的整数倍
			int				m_head_record_num;			// 文件头部尺寸所占据的记录个数
			int				m_record_length;			// 一条记录的字节数，round4,是4的整数倍,真实记录可能稍小
			int				m_head_round_size;			// 文件头部尺寸,以m_record_length为单位,是m_record_length的整数倍
			int				m_first_recordid;			// rid小于此值的记录均可由m_head_view直接写入
			BlockAes*		m_encryptor;				// 加密解密,文件头不加密

			char*			m_pod;						// 临时的单条记录的内存
			int				m_pod_size;					// 临时的单条记录的内存大小,比m_record_length大16字节
		protected://配置变量
			bool			m_delete_file;				// 默认删除文件
			bool			m_flag_update_count;		// 更新个数
		public:
			TableFile(int recordSize, int headSize,const char* tag=0, int viewsize = 8,int increase=8);
			virtual ~TableFile();
			bool Initialize(const char* fname,bool reset=false);
			bool IsInitialized(){ return m_initialized; }

			void ReleaseView();
			void SetDeleteFile(bool deleteFile){ m_delete_file = deleteFile; }
			void SetFlagUpdateCount(bool updateCount){ m_flag_update_count = updateCount; }

		public://读写记录
			int GetHeadSize(){ return m_head_size; }
			bool ReadHead(char*buf, int size, int offset = 0);
			bool WriteHead(const char*buf, int size,int count);
			
			const char* ReadDirect(int rid);
			bool Read(RecordId rid, char* record, int size);
			bool Write(RecordId rid, const char* record, int size);
			bool SetRecordCount(RecordId rid);
		public://统计信息
			ViewInfo GetViewInfo()const;
			const std::string& GetFileName()const{ return m_fname; }
			int GetFileSize()const{ return (m_max_viewid + 1)*m_view_size; }
			int GetViewSize()const{ return m_view_size; }
			int GetPageSize()const{ return m_increase_size; }
			int GetMemory()const;
			int GetRecordCount()const{ return m_record_count; }
			int GetRemapCount()const{ return m_remap_count; }
		protected:
			void SetTag(const char* tag);
			const char* ReadDirectImpl(int rid);
			bool ReadImpl(RecordId rid, char* record, int size);
			bool WriteImpl(RecordId rid, const char* record, int size);
			bool PrepareMapping(int maxSize);

			// 获取最后一个view的末尾在文件中的偏移量
			int GetMaxViewEnd()const{ return m_max_viewid*m_view_size+m_view_size;}
			int CalculateView(int offset);
			bool PrepareView(RecordId rid);

			void PrepareHead();

			const char* Encrypt(const char* record, int& len);
			const char* Decrypt(const char* record, int& len);
		};
	}//namespace ht
}//namespace qb
